package br.com.hs.nfe;

import br.com.hs.nfe.business.NotaFiscalBusiness;
import br.com.hs.nfe.certificado.*;
import br.com.hs.nfe.certificado.exception.HSCertificadoException;
import br.com.hs.nfe.common.enumeration.SituacaoNFeEnum;
import br.com.hs.nfe.common.to.*;
import br.com.hs.nfe.common.validation.exception.HSValidationException;
import br.com.hs.nfe.ws.exception.*;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

/**
 * Classe de integração das funções da biblioteca HSNF-e.
 * @author Ranlive Hrysyk
 */
public class NotaFiscalUtil {

    private static NotaFiscalBusiness notaFiscalBusiness;

    /**
     * Obtém a instância de NotaFiscalBusiness
     */
    private static NotaFiscalBusiness getNotaFiscalBusiness() {
        if (notaFiscalBusiness == null) {
            notaFiscalBusiness = new NotaFiscalBusiness();
        }
        return notaFiscalBusiness;
    }

    /**
     * Obtém um objeto CertificadoTO a partir de um arquivo.
     * @param caminho Caminho do arquivo de certificado.
     * @param senha Senha do certificado.
     */
    public static CertificadoTO createCertificadoTO(String caminho, String senha) throws HSCertificadoException {
        return Certificado.createCertificadoTO(caminho, senha);
    }

    /**
     * Valida a assinatura do XML da Nota Fiscal.
     * @param notaFiscalTO Nota Fiscal.
     * @return Se valido retorna true, caso contrário false.
     */
    public static boolean validarAssinaturaXML(NotaFiscalTO notaFiscalTO) throws HSCertificadoException {
        return Certificado.validarAssinaturaXML(notaFiscalTO.getXmlString());
    }

    /**
     * Valida um certificado e retorna as mensagens de erro.
     * @param certificadoTO Certificado
     * @return Lista de mensagens de erro ou empty(vazio) se não houver erros.
     */
    public static List<String> validarCertificadoTO(CertificadoTO certificadoTO) {
        return Certificado.validarCertificado(certificadoTO.getX509Certificate(), AppUtil.getEmitenteTO().getCNPJ());
    }

    /**
     * Assina o XML da Nota Fiscal e atribui o status ASSINADA.
     * @param notaFiscalTO Nota Fiscal a ser assinada.
     * @param certificadoTO Certificado de assinatura.
     */
    private static void assinarXML(NotaFiscalTO notaFiscalTO, CertificadoTO certificadoTO) throws HSCertificadoException {
        getNotaFiscalBusiness().assinar(notaFiscalTO, certificadoTO);
    }

    /**
     * Assina uma lista de notas fiscal com status VALIDADA e atribui o status ASSINADA.
     * @param listaNotas Notas fiscais assinadas
     * @param certificadoTO Certificado de assinatura.
     * @return Retorna a lista de notas fiscais assinadas.
     */
    public static List<NotaFiscalTO> assinarXML(List<NotaFiscalTO> listaNotas, CertificadoTO certificadoTO) throws HSCertificadoException {
        List<NotaFiscalTO> assinadas = new ArrayList<NotaFiscalTO>();
        for (NotaFiscalTO notaFiscalTO : listaNotas) {
            if (notaFiscalTO.getSituacao().equals(SituacaoNFeEnum.VALIDADA)) {
                assinarXML(notaFiscalTO, certificadoTO);
                if (notaFiscalTO.getSituacao().equals(SituacaoNFeEnum.ASSINADA)) {
                    assinadas.add(notaFiscalTO);
                }
            }
        }
        return assinadas;
    }

    /**
     * Converte um array de bytes para X509Certificate.
     * @param binaryCertificate Byte array a ser convertido.
     */
    public static X509Certificate getX509(byte[] binaryCertificate) throws HSCertificadoException {
        return CertificadoHelper.getX509(binaryCertificate);
    }

    /**
     * Converte X509Certificate para um array de bytes.
     * @param certificate Certificado a ser transformado.
     */
    public static byte[] getBytes(X509Certificate certificate) throws HSCertificadoException {
        return CertificadoHelper.getBytes(certificate);
    }

    /**
     * Valida os dados de um cliente.
     * @param clienteTO Cliente a ser validado.
     */
    public static void validarClienteTO(ClienteTO clienteTO) throws HSValidationException {
        getNotaFiscalBusiness().validarClienteTO(clienteTO);
    }

    /**
     * Valida os dados de um emitente.
     * @param emitenteTO Emitente a ser validado.
     */
    public static void validarEmitenteTO(EmitenteTO emitenteTO) throws HSValidationException {
        getNotaFiscalBusiness().validarEmitenteTO(emitenteTO);
    }

    /**
     * Valida os dados de um produto.
     * @param produtoTO Produto a ser validado.
     */
    public static void validarProdutoTO(ProdutoTO produtoTO) throws HSValidationException {
        getNotaFiscalBusiness().validarProdutoTO(produtoTO);
    }

    /**
     * Valida os dados da nota fiscal.
     * @param notaFiscalTO Nota fiscal a ser validado.
     */
    private static void validarNotaFiscalTO(NotaFiscalTO notaFiscalTO) throws HSValidationException {
        getNotaFiscalBusiness().validarNotaFiscalTO(notaFiscalTO);
    }

    /**
     * Valida os dados das notas fiscais com status EM DIGITAÇÂO.
     * @param listaNotas Lista de notas à validar.
     */
    public static void validarNotaFiscalTO(List<NotaFiscalTO> listaNotas) throws HSValidationException {
        for (NotaFiscalTO notaFiscalTO : listaNotas) {
            if (notaFiscalTO.getSituacao().equals(SituacaoNFeEnum.EM_DIGITACAO)) {
                validarNotaFiscalTO(notaFiscalTO);
            }
        }
    }

    /**
     * Envia uma NF-e para a Sefaz
     * <p><b>IMPORTANTE: Somente deverão constar no lote, NF-e's de mesmo tipo de emissão e da mesma versão.</b></p>
     * @param loteTO Lote de transmissão
     * @param certificadoTO Certificado de autenticação
     * @throws HSWebServiceException Exceções do Web Service
     * @throws HSConnectionClientException Exceções na conexão do cliente
     * @throws HSConnectionServerException Exceções na conexão do servidor
     * @throws HSTimeoutException Exceções de tempo esgotado
     * @throws HSProxyException Exceções de proxy
     * @throws HSSocketException Exceções de conexão
     */
    public static void transmitirLoteTO(LoteTO loteTO, CertificadoTO certificadoTO) throws HSWebServiceException, HSConnectionClientException, HSConnectionServerException, HSTimeoutException, HSProxyException, HSSocketException {
        getNotaFiscalBusiness().transmitir(loteTO, certificadoTO);
    }
}
